package org.ns.summer.example.service;

import com.alibaba.fastjson.JSON;
import org.ns.summer.beans.anns.Service;
import org.ns.summer.core.ResourceUtils;
import org.ns.summer.example.pojo.*;

import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;

@Service // 这是一个Service 、 扫盘的时候会被加载到容器
public class UserService {

    private static UserData userData;
    private static Map<String, UserInfo> userInfoIndexMap = new ConcurrentHashMap<>();
    private static Map<Long, UserInfo> userInfoIdIndexMap = new ConcurrentHashMap<>();
    private static Map<String, RoleInfo> roleInfoIndexMap = new ConcurrentHashMap<>();
    private static Map<Long, Set<String>> roleIdMappingIndexMap = new ConcurrentHashMap<>();
    static {
        try (InputStream inputStream = ResourceUtils.getInputStream(UserService.class.getClassLoader(), "userInfo.json");) {
            byte[] data = new byte[inputStream.available()];
            inputStream.read(data);
            String json = new String(data, "UTF-8");
            userData = JSON.parseObject(json, UserData.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        // hash 索引
        for (UserInfo userInfo : userData.getUserInfos()) {
            userInfoIndexMap.put(userInfo.getUsername(), userInfo);
            userInfoIdIndexMap.put(userInfo.getUserId(), userInfo);
        }

        for (RoleInfo roleInfo : userData.getRoleInfos()) {
            roleInfoIndexMap.put(roleInfo.getRoleKey(), roleInfo);
        }

        for (RoleMapping roleMapping : userData.getRoleMappings()) {
            long userId = roleMapping.getUserId();
            String roleKey = roleMapping.getRoleKey();
            RoleInfo roleInfo = roleInfoIndexMap.get(roleKey);
            if (roleInfo != null) {
                Set<String> roleInfos = roleIdMappingIndexMap.get(userId);
                if (roleInfos == null) {
                    roleInfos = new LinkedHashSet<>();
                    roleIdMappingIndexMap.put(userId, roleInfos);
                }
                roleInfos.add(roleInfo.getRoleKey());
            }
        }
    }

    public UserLoginResp login(String username, String password) {
        UserLoginResp resp = new UserLoginResp();
        UserInfo userInfo = userInfoIndexMap.get(username);
        if (userInfo == null) {
            resp.setState(1000001);
            resp.setMessage("用户名无效");
        } else if (password == null || password.isEmpty() || !password.equals(userInfo.getPassword())) {
            resp.setState(1000002);
            resp.setMessage("密码错误！");
        } else {
            long failureTime = System.currentTimeMillis() + (24 * 60 * 60 * 1000); // 1天失效
            String token = createToken(userInfo.getUserId(), failureTime);
            resp.setState(0);
            resp.setToken(token);
            resp.setUserId(userInfo.getUserId());
            resp.setMessage("登录成功");
        }
        return resp;
    }

    public UserInfoResp getUserInfo(Long userId) {
        UserInfoResp resp = new UserInfoResp();
        if (userId == null) {
            resp.setState(1000001);
            resp.setMessage("用户未登录");
        } else if (!userInfoIdIndexMap.containsKey(userId)) {
            resp.setState(1100001);
            resp.setMessage("用户不存在");
        } else {
            UserInfo userInfo = userInfoIdIndexMap.get(userId);
            resp.setUserId(userId);
            resp.setUsername(userInfo.getUsername());
            resp.setMessage("用户信息查询成功");
        }
        return resp;
    }

    // 简单创建一个token
    private String createToken(Long userId, long failureTime) {
        ByteBuffer byteBuffer = ByteBuffer.allocate(20);
        byteBuffer.putInt(ThreadLocalRandom.current().nextInt());
        byteBuffer.putLong(userId);
        byteBuffer.putLong(failureTime);
        byte[] bytes = byteBuffer.array();
        return Base64.getEncoder().encodeToString(bytes);
    }

    public UserInfo getUserInfoByUserId(Long userId) {
        if (userId == null) {
            return null;
        }
        return userInfoIdIndexMap.get(userId);
    }

    public Long getUserIdByToken(String token) {
        if (token == null || (token = token.trim()).isEmpty()) {
            return null;
        }
        try {
            byte[] bytes = Base64.getDecoder().decode(token);
            if (bytes.length != 20) {
                return null;
            }
            ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
            long userId = byteBuffer.getLong(4);
            long failureTime = byteBuffer.getLong(12);
            if (System.currentTimeMillis() > failureTime) {
                return null;
            } else {
                return userId;
            }
        } catch (Exception e) {
            return null;
        }
    }

    public String getTokeyByRequest(HttpServletRequest request) {
        String token = request.getHeader("token");
        if (token == null || token.trim().isEmpty()) {
            token = request.getParameter("token");
        }
        if (token != null) {
            token.trim();
        }
        return token;
    }

    public UserInfo getUserInfoByRequest(HttpServletRequest request) {
        String token = getTokeyByRequest(request);
        Long userId = getUserIdByToken(token);
        return getUserInfoByUserId(userId);
    }
    public boolean verifyRole(String[] roleKeys, Long userId) {
        if (userId == null) {
            return false;
        }
        if (roleKeys == null || roleKeys.length == 0) {
            return true;
        }
        Set<String> roleInfos = roleIdMappingIndexMap.get(userId);
        if (roleInfos == null) {
            return false;
        }
        for (String roleKey : roleKeys) {
            if (roleInfos.contains(roleKey)) {
                return true;
            }
        }
        return false;
    }
    public UserLoginResp toLoginFail() {
        UserLoginResp resp = new UserLoginResp();
        resp.setState(1000003);
        resp.setMessage("未登录");
        return resp;
    }
    public UserLoginResp toRoleFail() {
        UserLoginResp resp = new UserLoginResp();
        resp.setState(1000004);
        resp.setMessage("权限失败");
        return resp;
    }

}
